package initialize

import (
	"context"
	"fmt"
	"time"

	"gitee.com/war2001/NiuMaEasyGo/api"
	"gitee.com/war2001/NiuMaEasyGo/global"
	"gitee.com/war2001/NiuMaEasyGo/model"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/cache"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/database"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/middleware"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/queue"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/router"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/scheduler"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/storage"
	"gitee.com/war2001/NiuMaEasyGo/nm_core/websocket"
	"gitee.com/war2001/NiuMaEasyGo/service"
	"gitee.com/war2001/NiuMaEasyGo/utils"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	wcache "github.com/silenceper/wechat/v2/cache"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

// InitDatabase 初始化数据库并设置全局变量
func InitDatabase() (*gorm.DB, error) {
	db, err := database.InitFromGlobal()
	if err != nil {
		return nil, err
	}

	// 设置全局数据库变量
	global.DB = db.DB

	return db.DB, nil
}

// InitRedis 初始化Redis并设置全局变量
func InitRedis() (*redis.Client, wcache.Cache, error) {
	redis, redisOpts, err := cache.InitFromGlobal()
	if err != nil {
		return nil, nil, err
	}

	// 创建微信SDK使用的缓存
	redisCache := wcache.NewRedis(context.Background(), redisOpts)

	// 设置全局Redis变量
	global.Redis = redis.GetClient()
	global.WechatCache = redisCache

	return redis.GetClient(), redisCache, nil
}

// InitWebSocket 初始化WebSocket服务
func InitWebSocket() (*websocket.Manager, error) {
	if !global.Config.WebSocket.Enabled {
		zap.L().Info("WebSocket服务未启用")
		return nil, nil
	}

	// 创建WebSocket管理器
	wsManager := websocket.NewManager()

	// 启动WebSocket管理器
	wsManager.Start()

	// 设置全局WebSocket管理器变量
	global.WebSocketManager = wsManager

	zap.L().Info("WebSocket服务初始化成功")
	return wsManager, nil
}

// InitScheduler 初始化调度器
func InitScheduler() (*scheduler.Scheduler, error) {
	if !global.Config.Scheduler.Enabled {
		zap.L().Info("调度器未启用")
		return nil, nil
	}

	// 创建调度器配置
	config := &scheduler.Config{
		Timezone: global.Config.Scheduler.Timezone,
	}

	// 创建调度器
	sch, err := scheduler.NewScheduler(config)
	if err != nil {
		return nil, err
	}

	// 启动调度器
	sch.Start()

	// 设置全局调度器变量
	global.Scheduler = sch

	// 注册预定义任务
	for _, taskConfig := range global.Config.Scheduler.Tasks {
		if !taskConfig.Enabled {
			continue
		}

		// 创建任务
		task := scheduler.NewSimpleTask(taskConfig.Name, func(ctx context.Context) error {
			zap.L().Info("执行任务", zap.String("task", taskConfig.Name))
			// 这里可以根据任务名称执行不同的逻辑
			switch taskConfig.Name {
			case "clean_expired_tokens":
				// 清理过期令牌的逻辑
				return cleanExpiredTokens(ctx)
			case "database_backup":
				// 数据库备份的逻辑
				return databaseBackup(ctx)
			case "log_cleanup":
				// 日志清理的逻辑
				return logCleanup(ctx)
			case "login_log_cleanup":
				// 登录日志清理的逻辑
				return scheduler.LoginLogCleanupTask(ctx)
			default:
				zap.L().Warn("未知任务", zap.String("task", taskConfig.Name))
				return nil
			}
		})

		// 添加任务到调度器
		err := sch.AddTask(taskConfig.Spec, task)
		if err != nil {
			zap.L().Error("添加任务失败", zap.String("task", taskConfig.Name), zap.Error(err))
			continue
		}
	}

	zap.L().Info("调度器初始化成功", zap.Int("tasks", sch.GetTaskCount()))

	// 如果启用了分布式调度器，初始化分布式调度器
	if global.Config.Scheduler.Distributed.Enabled {
		if err := InitDistributedScheduler(); err != nil {
			zap.L().Error("分布式调度器初始化失败", zap.Error(err))
		}
	}

	return sch, nil
}

// InitDistributedScheduler 初始化分布式调度器
func InitDistributedScheduler() error {
	distConfig := global.Config.Scheduler.Distributed

	// 创建分布式调度器配置
	config := &scheduler.DistributedConfig{
		Timezone:         global.Config.Scheduler.Timezone,
		ExchangeName:     distConfig.ExchangeName,
		RoutingKeyPrefix: distConfig.RoutingKeyPrefix,
		IsPublisher:      distConfig.Publisher,
		IsConsumer:       distConfig.Consumer,
	}

	// 创建分布式调度器
	distSch, err := scheduler.NewDistributedScheduler(config)
	if err != nil {
		return err
	}

	// 启动分布式调度器
	if err := distSch.Start(); err != nil {
		return err
	}

	// 设置全局分布式调度器变量
	global.DistributedScheduler = distSch

	// 如果是发布者，注册预定义任务
	if distConfig.Publisher {
		for _, taskConfig := range distConfig.Tasks {
			if !taskConfig.Enabled {
				continue
			}

			// 添加任务到分布式调度器
			err := distSch.AddTask(
				taskConfig.Name,
				taskConfig.Topic,
				taskConfig.Spec,
				map[string]interface{}{},
			)
			if err != nil {
				zap.L().Error("添加分布式任务失败",
					zap.String("task", taskConfig.Name),
					zap.String("topic", taskConfig.Topic),
					zap.Error(err))
				continue
			}
		}
	}

	// 如果是消费者，注册任务处理函数
	if distConfig.Consumer {
		// 注册通知处理函数
		err := distSch.RegisterHandler("notification", func(ctx context.Context, task *scheduler.DistributedTask) error {
			zap.L().Info("处理通知任务",
				zap.String("id", task.ID),
				zap.String("name", task.Name),
				zap.Any("params", task.Params))
			// 这里实现通知发送逻辑
			return nil
		})
		if err != nil {
			zap.L().Error("注册通知处理函数失败", zap.Error(err))
		}

		// 注册同步处理函数
		err = distSch.RegisterHandler("sync", func(ctx context.Context, task *scheduler.DistributedTask) error {
			zap.L().Info("处理同步任务",
				zap.String("id", task.ID),
				zap.String("name", task.Name),
				zap.Any("params", task.Params))
			// 这里实现数据同步逻辑
			return nil
		})
		if err != nil {
			zap.L().Error("注册同步处理函数失败", zap.Error(err))
		}
	}

	zap.L().Info("分布式调度器初始化成功",
		zap.Bool("publisher", distConfig.Publisher),
		zap.Bool("consumer", distConfig.Consumer),
		zap.Int("tasks", len(distConfig.Tasks)))

	return nil
}

// InitMessageQueue 初始化消息队列
func InitMessageQueue() (*queue.RabbitMQ, error) {
	if !global.Config.Queue.Enabled {
		zap.L().Info("消息队列未启用")
		return nil, nil
	}

	// 仅支持RabbitMQ
	if global.Config.Queue.Provider != "rabbitmq" {
		zap.L().Warn("不支持的消息队列提供商", zap.String("provider", global.Config.Queue.Provider))
		return nil, nil
	}

	// 创建RabbitMQ配置
	config := &queue.Config{
		Host:         global.Config.Queue.RabbitMQ.Host,
		Port:         global.Config.Queue.RabbitMQ.Port,
		Username:     global.Config.Queue.RabbitMQ.Username,
		Password:     global.Config.Queue.RabbitMQ.Password,
		VHost:        global.Config.Queue.RabbitMQ.VHost,
		ExchangeName: global.Config.Queue.RabbitMQ.ExchangeName,
		QueueName:    global.Config.Queue.RabbitMQ.QueueName,
		RoutingKey:   global.Config.Queue.RabbitMQ.RoutingKey,
		ExchangeType: global.Config.Queue.RabbitMQ.ExchangeType,
		Durable:      global.Config.Queue.RabbitMQ.Durable,
		AutoDelete:   global.Config.Queue.RabbitMQ.AutoDelete,
		Exclusive:    global.Config.Queue.RabbitMQ.Exclusive,
		NoWait:       global.Config.Queue.RabbitMQ.NoWait,
	}

	// 创建RabbitMQ客户端
	mq, err := queue.NewRabbitMQ(config)
	if err != nil {
		return nil, err
	}

	// 设置全局消息队列变量
	global.MessageQueue = mq

	zap.L().Info("消息队列初始化成功")
	return mq, nil
}

// InitStorage 初始化存储服务
func InitStorage() (*storage.Manager, error) {
	if global.Config == nil || global.Config.Storage.Provider == "" {
		zap.L().Warn("存储配置不存在或未指定提供商，使用默认本地存储")
		// 创建默认本地存储配置
		localConfig := &storage.LocalConfig{
			RootPath:   "./uploads",
			BaseURL:    "http://localhost:8080/uploads",
			CreatePath: true,
		}
		// 创建本地存储
		localStorage, err := storage.NewLocalStorage(localConfig)
		if err != nil {
			return nil, fmt.Errorf("创建默认本地存储失败: %w", err)
		}
		// 创建存储管理器
		manager, err := storage.NewManager(localStorage)
		if err != nil {
			return nil, fmt.Errorf("创建存储管理器失败: %w", err)
		}
		return manager, nil
	}

	// 从配置创建存储管理器
	manager, err := storage.NewStorageFromConfig(&global.Config.Storage)
	if err != nil {
		return nil, fmt.Errorf("创建存储管理器失败: %w", err)
	}

	// 设置全局存储管理器
	global.StorageManager = manager

	zap.L().Info("存储服务初始化成功", zap.String("provider", global.Config.Storage.Provider))
	return manager, nil
}

// AutoMigrateDB 自动迁移数据库表结构
func AutoMigrateDB(db *gorm.DB) error {
	// 自动迁移数据库表结构
	err := db.AutoMigrate(
		// 基础用户相关模型
		&model.User{},
		&model.Role{},
		&model.Permission{},
		&model.UserRole{},
		&model.RolePermission{},

		// 系统管理相关模型
		&model.SysMenu{},        // 系统菜单
		&model.SysRole{},        // 系统角色
		&model.SysUserRole{},    // 用户角色关联
		&model.SysRoleMenu{},    // 角色菜单关联
		&model.SysUserMenu{},    // 用户菜单关联
		&model.SysDept{},        // 部门
		&model.SysRoleDept{},    // 角色部门关联
		&model.SysApplication{}, // 应用

		// 多租户相关模型
		&model.SysTenant{},            // 租户
		&model.SysTenantMenu{},        // 租户菜单关联
		&model.SysTenantPackage{},     // 租户套餐
		&model.SysTenantApplication{}, // 租户应用关联

		// 其他业务模型
		&model.WechatConfig{},
		&model.LoginLog{}, // 登录日志模型
		&model.File{},     // 文件模型
		&model.Order{},    // 订单模型
		&model.Product{},  // 产品模型
	)

	if err != nil {
		return err
	}

	// 创建默认系统管理员角色
	var adminRole model.SysRole
	result := db.Where("code = ?", "admin").First(&adminRole)
	if result.RowsAffected == 0 {
		adminRole = model.SysRole{
			Name:        "系统管理员",
			Code:        "admin",
			Description: "系统管理员，拥有所有权限",
			Sort:        1,
			Status:      1,
			DataScope:   "all",
			CreateBy:    "system",
		}
		if err := db.Create(&adminRole).Error; err != nil {
			zap.L().Error("创建系统管理员角色失败", zap.Error(err))
		} else {
			zap.L().Info("创建系统管理员角色成功")
		}
	}

	// 创建默认管理员用户
	var adminUser model.User
	result = db.Where("username = ?", "admin").First(&adminUser)
	if result.RowsAffected == 0 {
		// 使用bcrypt加密密码
		hashedPassword, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
		if err != nil {
			zap.L().Error("加密密码失败", zap.Error(err))
			return nil
		}

		adminUser = model.User{
			Username:    "admin",
			Password:    string(hashedPassword),
			Nickname:    "管理员",
			Avatar:      "",
			Email:       "admin@example.com",
			Phone:       "",
			Gender:      0,
			Status:      1,
			RoleID:      adminRole.ID,
			LastLoginAt: time.Now(),
		}

		if err := db.Create(&adminUser).Error; err != nil {
			zap.L().Error("创建管理员用户失败", zap.Error(err))
		} else {
			zap.L().Info("创建管理员用户成功")

			// 创建用户角色关联
			userRole := model.SysUserRole{
				UserID: uint64(adminUser.ID),
				RoleID: uint64(adminRole.ID),
			}
			if err := db.Create(&userRole).Error; err != nil {
				zap.L().Error("创建用户角色关联失败", zap.Error(err))
			} else {
				zap.L().Info("创建用户角色关联成功")
			}
		}
	}

	return nil
}

// InitServices 初始化服务并设置全局变量
func InitServices(db *gorm.DB, rdb *redis.Client) *service.Services {
	services := service.NewServices(db)

	// 设置全局服务变量
	global.Services = services

	return services
}

// InitUtils 初始化工具类并设置全局变量
func InitUtils(services *service.Services, redisCache wcache.Cache) *utils.Utils {
	utils := &utils.Utils{
		Wechat: utils.NewWechatUtil(services.WechatConfig, redisCache),
		// 添加其他工具类
	}

	// 设置全局工具变量
	global.Utils = utils

	return utils
}

// InitRouter 初始化路由
func InitRouter(services *service.Services, utils *utils.Utils) (*gin.Engine, *router.ControllerRegistry) {
	// 设置gin模式
	if global.Config.App.Mode == "production" {
		gin.SetMode(gin.ReleaseMode)
	} else if global.Config.App.Mode == "test" {
		gin.SetMode(gin.TestMode)
	} else {
		gin.SetMode(gin.DebugMode)
	}

	r := gin.New()

	// 注册全局中间件
	middleware.RegisterMiddlewares(r)

	// 添加根路径处理程序
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Welcome to NiuMaEasyGo API",
			"version": global.Config.App.Version,
			"status":  "running",
		})
	})

	// API路由组
	apiGroup := r.Group(global.Config.App.APIPrefix)

	// 添加API根路径处理程序
	apiGroup.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Welcome to NiuMaEasyGo API",
			"version": global.Config.App.Version,
			"status":  "running",
		})
	})

	// 公共API路由组
	publicGroup := apiGroup.Group("/public")
	middleware.RegisterPublicMiddlewares(publicGroup)

	// 需要认证的API路由组
	authGroup := apiGroup.Group("/auth")
	middleware.RegisterAuthMiddlewares(authGroup)

	// 登录路由组
	loginGroup := apiGroup.Group("/auth")
	middleware.RegisterLoginMiddlewares(loginGroup)

	// 创建控制器注册表
	registry := router.NewControllerRegistry(global.DB)

	// 创建权限服务
	permissionService := service.NewPermissionService(global.DB, global.ControllerRegistry)

	// 手动注册已知的控制器
	// 这里可以注册一些核心控制器，其他控制器通过自动发现机制注册
	registry.RegisterController(api.NewAuthController(services.User))
	registry.RegisterController(api.NewUserController(services.User, permissionService))
	registry.RegisterController(api.NewWechatConfigController(services.WechatConfig, utils.Wechat))
	registry.RegisterController(api.NewLoginLogController(services.LoginLog))
	registry.RegisterController(api.NewFileController(services.File))
	registry.RegisterController(api.NewMenuController(services.User))

	// 自动发现并注册其他控制器
	// 这里可以指定控制器所在的目录，系统会自动扫描并注册
	controllerDir := "api"
	err := registry.AutoDiscoverControllers(controllerDir, services)
	if err != nil {
		zap.L().Warn("自动发现控制器失败，仅使用手动注册的控制器", zap.Error(err))
	}

	// 将所有控制器注册到路由
	registry.RegisterRoutes(r, global.Config.App.APIPrefix)

	// WebSocket路由
	if global.Config.WebSocket.Enabled && global.WebSocketManager != nil {
		if wsManager, ok := global.WebSocketManager.(*websocket.Manager); ok {
			r.GET(global.Config.WebSocket.Path, func(c *gin.Context) {
				wsManager.ServeWs(c)
			})
			zap.L().Info("WebSocket路由已注册", zap.String("path", global.Config.WebSocket.Path))
		}
	}

	return r, registry
}

// 任务处理函数
func cleanExpiredTokens(ctx context.Context) error {
	// 这里实现清理过期令牌的逻辑
	zap.L().Info("清理过期令牌")
	// 示例：清理Redis中的过期JWT黑名单
	if global.Redis != nil {
		pattern := global.Config.JWT.BlacklistPrefix + "*"
		keys, err := global.Redis.Keys(ctx, pattern).Result()
		if err != nil {
			return err
		}

		count := 0
		for _, key := range keys {
			// 检查是否过期
			ttl, err := global.Redis.TTL(ctx, key).Result()
			if err != nil {
				continue
			}

			// 如果TTL小于0或者小于宽限期，则删除
			if ttl < 0 || ttl < time.Duration(global.Config.JWT.BlacklistGracePeriod)*time.Second {
				_, err := global.Redis.Del(ctx, key).Result()
				if err == nil {
					count++
				}
			}
		}

		zap.L().Info("清理过期令牌完成", zap.Int("count", count))
	}

	return nil
}

func databaseBackup(ctx context.Context) error {
	// 这里实现数据库备份的逻辑
	zap.L().Info("执行数据库备份")
	// 示例：可以调用系统命令执行备份
	// 或者使用数据库提供的备份API
	return nil
}

func logCleanup(ctx context.Context) error {
	// 这里实现日志清理的逻辑
	zap.L().Info("执行日志清理")
	// 示例：清理过期的日志文件
	// 可以根据配置的保留天数删除旧日志
	return nil
}
